package com.leyou.user.service.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.leyou.auth.inter.pojo.UserInfo;
import com.leyou.common.bean.Constant;
import com.leyou.common.bean.PageResult;
import com.leyou.common.bean.Result;
import com.leyou.common.bean.ResultCode;
import com.leyou.common.util.CodecUtils;
import com.leyou.common.util.IdWorker;
import com.leyou.common.util.NumberUtils;
import com.leyou.common.util.StringUtil;
import com.leyou.user.inter.dto.*;
import com.leyou.user.inter.pojo.User;
import com.leyou.user.inter.vo.UserPageVO;
import com.leyou.user.service.config.IdWorkerProperties;
import com.leyou.user.service.interceptor.LoginInterceptor;
import com.leyou.user.service.mapper.UserMapper;
import com.leyou.user.service.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author zqq
 * @ClassName UserServiceImpl
 * @Description
 * @date 2020/3/4-16:37
 */
@Service
@Slf4j
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private AmqpTemplate amqpTemplate;

    @Autowired
    private IdWorkerProperties idWorkerProperties;

    @Override
    public Result<Boolean> checkData(String data, Integer type) {
        User record = new User();
        switch (type) {
            case 1:
                record.setUsername(data);
                break;
            case 2:
                record.setPhone(data);
                break;
            default:
                return null;
        }
        int result = 0;
        try {
            result = this.userMapper.selectCount(record);
        } catch (Exception e) {
            log.error("sql异常", e);
            return Result.newFailure(ResultCode.S_SYSTEM_EXCEPTION);
        }
        return Result.newSuccess(result == 0);
    }

    @Override
    public Result<Boolean> sendVerifyCode(String phone, Integer type) {
        // 生成验证码
        String code = NumberUtils.generateCode(6);
        try {
            // 发送短信
            Map<String, String> msg = new HashMap<>();
            msg.put("phone", phone);
            msg.put("code", code);
            // 将code存入redis
            if (type == 0) {
                this.amqpTemplate.convertAndSend("leyou.sms.exchange", "sms.verify.code", msg);
                this.redisTemplate.opsForValue().set(Constant.KEY_REGISTER_CODE + phone, code, 300, TimeUnit.SECONDS);
            } else {
                this.amqpTemplate.convertAndSend("leyou.sms.exchange", "sms.verify.code", msg);
                this.redisTemplate.opsForValue().set(Constant.KEY_LOGIN_CODE + phone, code, 300, TimeUnit.SECONDS);
            }
            return Result.newSuccess(true);
        } catch (Exception e) {
            log.error("发送短信失败。phone：{}， code：{}", phone, code);
            return Result.newFailure(ResultCode.S_SEND_SMS_ERROR);
        }
    }

    @Override
    @Transactional
    public Result<Boolean> register(UserRegisterDTO dto) {
        // 校验短信验证码
        String cacheCode = this.redisTemplate.opsForValue().get(Constant.KEY_REGISTER_CODE + dto.getPhone());
        if (!StringUtils.equals(dto.getCode(), cacheCode)) {
            return Result.newFailure(ResultCode.V_VERIFYCODE_ERROR);
        }

        //检查是否已有账号
        int count1 = 0, count2 = 0;
        try {
            count1 = this.userMapper.selectCount(new User(dto.getUsername(), null));
            count2 = this.userMapper.selectCount(new User(null, dto.getPhone()));
        } catch (Exception e) {
            log.error("sql异常", e);
            return Result.newFailure(ResultCode.S_SYSTEM_EXCEPTION);
        }
        if (count1 > 0 || count2 > 0) {
            return Result.newFailure(ResultCode.USER_ALREADY_HAVE_EXIST);
        }

        // 生成盐
        String salt = CodecUtils.generateSalt();
        User user = new User();
        user.setSalt(salt);
        user.setIsDelete(false);
        user.setSex(0);
        user.setIsFlag(true);
        user.setIsLocked(false);
        user.setUsername(dto.getUsername());
        user.setPhone(dto.getPhone());

        // 对密码加密
        user.setPassword(CodecUtils.md5Hex(dto.getPassword(), salt));

        IdWorker idWorker = new IdWorker(idWorkerProperties.getWorkerId(),idWorkerProperties.getDatacenterId());
        user.setId(idWorker.nextId());
        user.setCreateDate(new Date());
        // 添加到数据库
        int result = 0;
        try {
            result = this.userMapper.insertSelective(user);
            //添加角色表
            this.userMapper.insertUserAndRole(user.getId(),2L);
        } catch (Exception e) {
            log.error("sql异常", e);
            return Result.newFailure(ResultCode.S_SYSTEM_EXCEPTION);
        }
        if (result == 0)
            return Result.newFailure(ResultCode.S_SYSTEM_EXCEPTION);
        // 注册成功，删除redis中的记录
        this.redisTemplate.delete(Constant.KEY_REGISTER_CODE + user.getPhone());
        return Result.newSuccess(true);
    }

    @Override
    public Result<User> queryUser(UserLoginDTO dto) {
        if (dto.getType() == null || !StringUtil.isEmpty(dto.getUsername())) {
            return Result.newFailure(ResultCode.PARAM_NOT_NULL);
        }
        User record = new User();
        if (dto.getType() == 1) {
            if (!StringUtil.isEmpty(dto.getPassword()))
                return Result.newFailure(ResultCode.PARAM_NOT_NULL);
            //判断是用户名还是手机号
            Pattern p = Pattern.compile("^[1]([3-9])[0-9]{9}$");
            Matcher m = p.matcher(dto.getUsername());
            if (m.matches()) {
                record.setPhone(dto.getUsername());
            } else {
                record.setUsername(dto.getUsername());
            }
        } else if (dto.getType() == 2) {
            if (!StringUtil.isEmpty(dto.getCode()))
                return Result.newFailure(ResultCode.PARAM_NOT_NULL);
            // 校验短信验证码
            String cacheCode = this.redisTemplate.opsForValue().get(Constant.KEY_LOGIN_CODE + dto.getUsername());
            if (!StringUtils.equals(dto.getCode(), cacheCode)) {
                return Result.newFailure(ResultCode.V_VERIFYCODE_ERROR);
            }
            record.setPhone(dto.getUsername());
        }
        User user = null;
        try {
            user = this.userMapper.selectOne(record);
        } catch (Exception e) {
            log.error("sql异常", e);
            return Result.newFailure(ResultCode.S_SYSTEM_EXCEPTION);
        }
        // 校验用户
        if (user == null)
            return Result.newFailure(ResultCode.USER_NOT_EXIST);
        if (user.getIsDelete())
            return Result.newFailure(ResultCode.USER_ACCOUNT_ENABLED);
        if (user.getIsLocked())
            return Result.newFailure(ResultCode.USER_ACCOUNT_LOCKED);

        if (dto.getType() == 1) {
            // 校验密码
            if (!user.getPassword().equals(CodecUtils.md5Hex(dto.getPassword(), user.getSalt()))) {
                return Result.newFailure(ResultCode.USER_LOGIN_ERROR);
            }
        } else if (dto.getType() == 2) {
            // 登录成功，删除redis中的记录
            this.redisTemplate.delete(Constant.KEY_LOGIN_CODE + user.getPhone());
        }
        // 用户名密码都正确
        return Result.newSuccess(user);
    }

    @Override
    public Result<PageResult<UserPageVO>> queryUserByPage(UserPageDTO dto) {
        Example example = new Example(User.class);
        Example.Criteria criteria = example.createCriteria();
        // 搜索条件
        if (StringUtil.isEmpty(dto.getKey())) {
            criteria.andLike("username", "%" + dto.getKey() + "%").orEqualTo("phone", dto.getKey());
        }
        if (dto.getIsLocked() != null) {
            criteria.andEqualTo("isIocked", dto.getIsLocked());
        }
        // 分页条件
        PageHelper.startPage(dto.getPage(), dto.getRows());

        // 添加排序
        example.setOrderByClause("create_date desc");
        List<User> users = null;
        try {
            users = this.userMapper.selectByExample(example);
        } catch (Exception e) {
            log.error("sql异常", e);
            return Result.newFailure(ResultCode.S_SYSTEM_EXCEPTION);
        }
        PageInfo<User> pageInfo = new PageInfo<>(users);

        List<UserPageVO> userVO = new ArrayList<>();
        users.forEach(user -> {
            UserPageVO vo = new UserPageVO();
            // copy共同属性的值到新的对象
            BeanUtils.copyProperties(user, vo);
            userVO.add(vo);
        });
        return Result.newSuccess(new PageResult<UserPageVO>(pageInfo.getTotal(), pageInfo.getPages(), userVO));
    }

    @Override
    @Transactional
    public Result addUser(UserAddDto dto) {
        if (dto.getRoles() == null || dto.getRoles().size() == 0) {
            return Result.newFailure(ResultCode.USER_SET_ROLE_EXIST);
        }
        //检查是否已有账号
        int count1 = 0, count2 = 0;
        try {
            count1 = this.userMapper.selectCount(new User(dto.getUsername(), null));
            count2 = this.userMapper.selectCount(new User(null, dto.getPhone()));
        } catch (Exception e) {
            log.error("sql异常", e);
            return Result.newFailure(ResultCode.S_SYSTEM_EXCEPTION);
        }
        if (count1 > 0 || count2 > 0) {
            return Result.newFailure(ResultCode.USER_ALREADY_HAVE_EXIST);
        }

        // 生成盐
        String salt = CodecUtils.generateSalt();
        User user = new User();
        user.setSalt(salt);
        user.setIsDelete(false);
        user.setSex(0);
        user.setIsFlag(false);
        user.setIsLocked(false);
        user.setUsername(dto.getUsername());
        user.setPhone(dto.getPhone());
        // 对密码加密
        if(!StringUtil.isEmpty(dto.getPassword())){
            dto.setPassword("123456");
        }
        user.setPassword(CodecUtils.md5Hex(dto.getPassword(), salt));
        user.setName(dto.getName());

        // 强制设置不能指定的参数为null
        IdWorker idWorker = new IdWorker(idWorkerProperties.getWorkerId(), idWorkerProperties.getDatacenterId());
        user.setId(idWorker.nextId());
        user.setCreateDate(new Date());
        try {
            int count = this.userMapper.insertSelective(user);
            if (count == 0)
                return Result.newFailure(ResultCode.S_SYSTEM_EXCEPTION);
        } catch (Exception e) {
            log.error("sql异常", e);
            return Result.newFailure(ResultCode.S_SYSTEM_EXCEPTION);
        }
        //添加用户角色关联表
        for (Long role : dto.getRoles()) {
            this.userMapper.insertUserAndRole(user.getId(), role);
        }
        return Result.newSuccess();
    }

    @Override
    public Result deleteUser(UserUpdateDTO dto) {
        User user = new User();
        user.setId(dto.getId());
        if (dto.getIsDelete()) {
            user.setIsDelete(false);
        } else {
            user.setIsDelete(true);
        }
        return this.updateUser(user);
    }

    @Override
    public Result lockedUser(UserUpdateDTO dto) {
        User user = new User();
        user.setId(dto.getId());
        if (dto.getIsLocked()) {
            user.setIsLocked(false);
        } else {
            user.setIsLocked(true);
            user.setLockedDate(new Date());
            user.setLockedDay(dto.getLockedDay());
        }
        return this.updateUser(user);
    }

    @Override
    public Result resetUser(UserUpdateDTO dto) {
        User user = new User();
        user.setId(dto.getId());
        Result<User> userResult = this.getUserInfo();
        if(!userResult.success())
            return userResult;
        // 对密码加密
        user.setPassword(CodecUtils.md5Hex("123456", userResult.getData().getSalt()));
        return this.updateUser(user);
    }

    @Override
    @Transactional
    public Result updateUserAndRole(UserUpdateDTO dto) {
        if(dto.getRoles().size() == 0){
            return Result.newFailure(ResultCode.PARAM_NULL_ERROR);
        }
        User user = new User();
        user.setId(dto.getId());
        user.setUpdateDate(new Date());
        if(dto.getRoles().size() == 1 && dto.getRoles().get(0) == 2L){
            user.setIsFlag(true);
        }else{
            user.setIsFlag(false);
        }
        try {
            this.userMapper.deleteUserAndRole(dto.getId());
            for (Long role : dto.getRoles()) {
                userMapper.insertUserAndRole(dto.getId(), role);
            }
            this.userMapper.updateByPrimaryKeySelective(user);
        } catch (Exception e) {
            log.error("sql异常", e);
            return Result.newFailure(ResultCode.S_SYSTEM_EXCEPTION);
        }
        //修改用户角色，如果当前用户在线，让此用户下线
        String key = Constant.KEY_TOKEN_ID + dto.getId();
        Boolean bool = redisTemplate.hasKey(key);
        if(bool){
            redisTemplate.delete(key);
        }
        return Result.newSuccess();
    }

    @Override
    public Result<UpdateMyInfo> queryUserInfo() {
        Result<User> userResult = this.getUserInfo();
        if(!userResult.success())
            return Result.newFailure(userResult.getCode(),userResult.getMessage());
        UpdateMyInfo vo = new UpdateMyInfo();
        // copy共同属性的值到新的对象
        BeanUtils.copyProperties(userResult.getData(), vo);
        return Result.newSuccess(vo);
    }

    @Override
    public Result updateMyInfo(UpdateMyInfo dto) {
        UserInfo userInfo = LoginInterceptor.getLoginUser();
        User user = new User();
        user.setId(userInfo.getId());
        if(StringUtil.isEmpty(dto.getHeadImg()))
            user.setHeadImg(dto.getHeadImg());
        if(StringUtil.isEmpty(dto.getUsername()))
            user.setUsername(dto.getUsername());
        if(StringUtil.isEmpty(dto.getPhone()))
            user.setPhone(dto.getPhone());
        if(StringUtil.isEmpty(dto.getName()))
            user.setName(dto.getName());
        if(dto.getBirthDate() != null)
            user.setBirthDate(dto.getBirthDate());
        if(dto.getSex() != null)
            user.setSex(dto.getSex());
        if(StringUtil.isEmpty(dto.getAdress()))
            user.setAdress(dto.getAdress());

        if(StringUtil.isEmpty(dto.getPassword())){
            Result<User> userResult = this.getUserInfo();
            if(!userResult.success())
                return userResult;
            User entity = userResult.getData();
            String salt = entity.getSalt();
            // 对密码加密
            user.setPassword(CodecUtils.md5Hex(dto.getPassword(), salt));
        }
        return this.updateUser(user);
    }

    public Result updateUser(User user){
        user.setUpdateDate(new Date());
        try {
            this.userMapper.updateByPrimaryKeySelective(user);
        } catch (Exception e) {
            log.error("sql异常", e);
            return Result.newFailure(ResultCode.S_SYSTEM_EXCEPTION);
        }
        return Result.newSuccess();
    }

    @Override
    public Result sendOldSMS() {
        Result<User> userResult = this.getUserInfo();
        if(!userResult.success())
            return userResult;
        String phone = userResult.getData().getPhone();
        // 生成验证码
        String code = NumberUtils.generateCode(6);
        try {
            // 发送短信
            Map<String, String> msg = new HashMap<>();
            msg.put("phone", phone);
            msg.put("code", code);
            // 将code存入redis
            this.amqpTemplate.convertAndSend("leyou.sms.exchange", "sms.verify.code", msg);
            this.redisTemplate.opsForValue().set(Constant.KEY_BIND_OLD_CODE + phone, code, 300, TimeUnit.SECONDS);
        } catch (Exception e) {
            log.error("发送短信失败。phone：{}， code：{}", phone, code);
            return Result.newFailure(ResultCode.S_SEND_SMS_ERROR);
        }
        return Result.newSuccess();
    }

    @Override
    public Result verifyOldCode(String code) {
        Result<User> userResult = this.getUserInfo();
        if(!userResult.success())
            return userResult;
        // 校验短信验证码
        String cacheCode = this.redisTemplate.opsForValue().get(Constant.KEY_BIND_OLD_CODE + userResult.getData().getPhone());
        if (!StringUtils.equals(code, cacheCode)) {
            return Result.newFailure(ResultCode.V_VERIFYCODE_ERROR);
        }
        return Result.newSuccess();
    }

    @Override
    public Result sendNewSMS(String phone) {
        if(!StringUtil.isEmpty(phone))
            return Result.newFailure(ResultCode.PARAM_NOT_NULL);
        //查看手机号是否已被绑定过
        User user = new User();
        user.setPhone(phone);
        int count = 0;
        try {
            count = this.userMapper.selectCount(user);
        } catch (Exception e) {
            log.error("sql异常", e);
            return Result.newFailure(ResultCode.S_SYSTEM_EXCEPTION);
        }
        if(count > 0){
            return Result.newFailure(ResultCode.USER_ALREADY_BIND_FAIL);
        }
        // 生成验证码
        String code = NumberUtils.generateCode(6);
        try {
            // 发送短信
            Map<String, String> msg = new HashMap<>();
            msg.put("phone", phone);
            msg.put("code", code);
            // 将code存入redis
            this.amqpTemplate.convertAndSend("leyou.sms.exchange", "sms.verify.code", msg);
            this.redisTemplate.opsForValue().set(Constant.KEY_BIND_NEW_CODE + phone, code, 300, TimeUnit.SECONDS);
        } catch (Exception e) {
            log.error("发送短信失败。phone：{}， code：{}", phone, code);
            return Result.newFailure(ResultCode.S_SEND_SMS_ERROR);
        }
        return Result.newSuccess();
    }

    @Override
    public Result verifyNewCode(String phone,String code) {
        String cacheCode = this.redisTemplate.opsForValue().get(Constant.KEY_BIND_NEW_CODE + phone);
        if (!StringUtils.equals(code, cacheCode)) {
            return Result.newFailure(ResultCode.V_VERIFYCODE_ERROR);
        }

        UserInfo userInfo = LoginInterceptor.getLoginUser();
        //验证通过，修改绑定手机
        User user = new User();
        user.setId(userInfo.getId());
        user.setPhone(phone);
        return this.updateUser(user);
    }

    public Result<User> getUserInfo(){
        UserInfo userInfo = LoginInterceptor.getLoginUser();
        User user = null;
        try {
            user = this.userMapper.selectByPrimaryKey(userInfo.getId());
        } catch (Exception e) {
            log.error("sql异常", e);
            return Result.newFailure(ResultCode.S_SYSTEM_EXCEPTION);
        }
        if(user == null){
            return Result.newFailure(ResultCode.S_SYSTEM_DATA_EXCEPTION);
        }
        return Result.newSuccess(user);
    }
}
